package feeinterface.protocol.utils;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 对象转化
 * 
 * @author 黄杰
 * 
 */
public class Translate {
	/**
	 * 数组转化为流
	 * 
	 * @param fieldName
	 * @param array
	 * @param out
	 * @throws Exception
	 */
	@SuppressWarnings("all")
	public static void translateArrayToStream(String fieldName, Object array,
			DataOutputStream out) throws Exception {

		if (array == null) {
			throw new Exception("出现空值，请检查!");
			// return;

		}
		Class fieldType = array.getClass();
		if (!fieldType.isArray()) {
			throw new Exception("" + fieldType + "不是数组类型");
		}

		int arrayLen = Array.getLength(array);

		out.writeInt(arrayLen);

		Class elemType = fieldType.getComponentType();
		// Object array = Array.newInstance(elemType, arrayLen);
		for (int n = 0; n < arrayLen; n++) {
			Object fvalue = Array.get(array, n);
			if (elemType == short.class || elemType == Short.class) {
				if (fvalue == null) {
					out.writeShort(0);
				} else {
					out.writeShort((Short) Array.get(array, n));
				}

			} else if (elemType == int.class || elemType == Integer.class) {
				if (fvalue == null) {
					out.writeInt(0);
				} else {
					out.writeInt((Integer) Array.get(array, n));
				}

			} else if (elemType == byte.class || elemType == Byte.class) {
				if (fvalue == null) {
					out.writeByte(0);
				} else {
					out.writeByte((Byte) Array.get(array, n));
				}

			} else if (elemType == long.class || elemType == Long.class) {
				if (fvalue == null) {
					out.writeLong(0);
				} else {
					out.writeLong((Long) Array.get(array, n));
				}

			} else if (elemType == String.class) {
				byte[] bs = "".getBytes("utf-8");
				if (fvalue != null) {
					bs = ((String) Array.get(array, n)).getBytes("utf-8");
				}
				out.writeInt(bs.length);
				out.write(bs);

			} else {
				if (elemType.isArray()) {//
					throw new Exception("数组里元素不支持的数组类型" + elemType);
				} else if (elemType.isPrimitive()) {
					throw new Exception("数组里元素不支持的原始类型" + elemType);
				} else { // 对象

					if (fvalue == null) {
						throw new Exception("数组里对象元素为null");
					}
					translateObjectToStream(Array.get(array, n), out);

				}
			}
		}

	}

	/**
	 * 对象转化为流
	 * 
	 * @param obj
	 * @param out
	 * @throws Exception
	 */
	@SuppressWarnings("all")
	public static void translateObjectToStream(Object obj, DataOutputStream out)
			throws Exception {

		Class c = obj.getClass();
		Field[] fields = c.getDeclaredFields();
		Map<String, Object> fieldsNameValues = new HashMap<String, Object>();
		Map<String, Field> fieldsNameField = new HashMap<String, Field>();
		String[] values = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			int mod = field.getModifiers();
			values[i] = field.getName();
			fieldsNameValues.put(field.getName(), field.get(obj));
			fieldsNameField.put(field.getName(), field);
		}
		try {
			for (int i = 0; i < values.length; i++) {
				String fieldName = values[i];

				Field field = fieldsNameField.get(fieldName);

				Object fvalue = field.get(obj);

				Class<?> fieldType = field.getType();

				if (fieldType == short.class || fieldType == Short.class) {
					// field.set(obj, in.readShort());
					if (fvalue == null)
						out.writeShort(0);
					else
						out.writeShort((Short) field.get(obj));
				} else if (fieldType == int.class || fieldType == Integer.class) {
					if (fvalue == null)
						out.writeInt(0);
					else
						out.writeInt((Integer) field.get(obj));
				} else if (fieldType == byte.class || fieldType == Byte.class) {
					if (fvalue == null)
						out.writeByte(0);
					else {
						out.writeByte((Byte) field.get(obj));
					}
				} else if (fieldType == long.class || fieldType == Long.class) {
					if (fvalue == null)
						out.writeLong(0);
					else
						out.writeLong((Long) field.get(obj));
				} else if (fieldType == String.class) {
					byte[] bs = "".getBytes("utf-8");
					if (fvalue != null) {
						bs = ((String) field.get(obj)).getBytes("utf-8");
					}

					out.writeInt(bs.length);
					out.write(bs);
					// out.writeUTF(field.get(obj) + "");
				} else {
					if (fieldType.isArray()) {
						if (fvalue == null) {
							out.writeInt(0);
						} else {
							translateArrayToStream(fieldName, field.get(obj),
									out);
						}

					} else {
						if (fieldType.isPrimitive()) {
							throw new Exception("java bean里的" + fieldName
									+ "属性的类型" + fieldType + "不支持！");
						} else {
							translateObjectToStream(field.get(obj), out);
						}
					}
				}
			}
		} catch (Exception e) {
			throw new Exception("seq属性配置不正确或者配置的javabean与二进制流格式不匹配导致解析出错");
		}

	}

	/**
	 * 流转化为数组
	 * 
	 * @param fieldName
	 * @param t
	 * @param in
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("all")
	public static Object translateArrayFromStream(String fieldName, Class t,
			DataInputStream in) throws Exception {

		Class fieldType = t;
		if (!fieldType.isArray()) {
			throw new Exception("" + fieldType + "不是数组类型");
		}

		int arrayLen = 0;
		arrayLen = in.readInt();
		Class elemType = fieldType.getComponentType();
		Object array = Array.newInstance(elemType, arrayLen);
		for (int n = 0; n < arrayLen; n++) {
			if (elemType == short.class || elemType == Short.class) {
				Array.setShort(array, n, in.readShort());

			} else if (elemType == int.class || elemType == Integer.class) {
				Array.setInt(array, n, in.readInt());

			} else if (elemType == byte.class || elemType == Byte.class) {
				Array.setByte(array, n, in.readByte());

			} else if (elemType == long.class || elemType == Long.class) {
				Array.setLong(array, n, in.readLong());

			} else if (elemType == String.class) {
				int len = in.readInt();
				byte[] bs = new byte[len];
				in.readFully(bs);
				String s = new String(bs, "utf-8");
				Array.set(array, n, s);
				// Array.set(array, n, in.readUTF());

			} else {
				if (elemType.isArray()) {//
					throw new Exception("数组里元素不支持的数组类型" + elemType);
				} else if (elemType.isPrimitive()) {
					throw new Exception("数组里元素不支持的原始类型" + elemType);
				} else {
					Array.set(array, n, translateObjectFromStream(elemType, in));

				}
			}
		}
		return array;

	}

	/**
	 * 流转化为对象
	 * 
	 * @param c
	 * @param in
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("all")
	public static Object translateObjectFromStream(Class c, DataInputStream in)
			throws Exception {

		Field[] fields = c.getDeclaredFields();
		Object obj = c.newInstance();
		Map<String, Object> fieldsNameValues = new HashMap<String, Object>();
		Map<String, Field> fieldsNameField = new HashMap<String, Field>();
		String[] values = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			int mod = field.getModifiers();

			values[i] = field.getName();
			fieldsNameValues.put(field.getName(), field.get(obj));
			fieldsNameField.put(field.getName(), field);
		}

		try {
			for (int i = 0; i < values.length; i++) {
				String fieldName = values[i];
				Field field = fieldsNameField.get(fieldName);

				Class fieldType = field.getType();

				if (fieldType == short.class || fieldType == Short.class) {
					field.set(obj, in.readShort());
				} else if (fieldType == int.class || fieldType == Integer.class) {
					field.set(obj, in.readInt());
				} else if (fieldType == byte.class || fieldType == Byte.class) {
					field.set(obj, in.readByte());
				} else if (fieldType == long.class || fieldType == Long.class) {
					field.set(obj, in.readLong());
				} else if (fieldType == String.class) {
					int len = in.readInt();
					byte[] bs = new byte[len];
					in.readFully(bs);
					String s = new String(bs, "utf-8");

					field.set(obj, s);
				} else {
					if (fieldType.isArray()) {
						field.set(
								obj,
								translateArrayFromStream(fieldName, fieldType,
										in));

					} else {
						if (fieldType.isPrimitive()) {
							throw new Exception("java bean里的" + fieldName
									+ "属性的类型" + fieldType + "不支持！");
						} else {

							field.set(obj,
									translateObjectFromStream(fieldType, in));
						}

					}
				}
			}
		} catch (Exception e) {
			// e.printStackTrace();
			throw new Exception("seq属性配置不正确或者配置的javabean与二进制流格式不匹配导致解析出错");
		}
		return obj;

	}

	/**
	 * 
	 * @param obj
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("all")
	public static byte[] translateObjectToStream(Object obj) throws Exception {
		if (obj == null)
			return null;
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		DataOutputStream dout = new DataOutputStream(bout);
		try {
			Translate.translateObjectToStream(obj, dout);
		} catch (Exception e) {
			throw new Exception("seq属性配置不正确或者配置的javabean与二进制流格式不匹配导致解析出错");
		}
		return bout.toByteArray();
	}

	public static void main(String[] args) throws Exception {

		// 构造一个输出流
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		DataOutputStream dout = new DataOutputStream(bout);

		dout.writeInt(12);
		dout.writeInt(3);
		dout.write(new byte[] { 1, 3, 34 });
		dout.writeByte(12);
		String s = "123中国";
		dout.writeInt(s.getBytes("utf-8").length);
		dout.write(s.getBytes("utf-8"));

		dout.writeShort(12);
		dout.writeShort(1);
		String s2 = "大众";
		dout.writeInt(s2.getBytes("utf-8").length);
		dout.write(s2.getBytes("utf-8"));
		dout.writeInt(3);
		dout.writeShort(5);
		dout.writeInt(2);
		s2 = "好";
		dout.writeInt(s2.getBytes("utf-8").length);
		dout.write(s2.getBytes("utf-8"));
		s2 = "好2";
		dout.writeInt(s2.getBytes("utf-8").length);
		dout.write(s2.getBytes("utf-8"));
		dout.writeInt(3);
		dout.write(new byte[] { 2, 3, 4 });
		dout.close();

		// 把输出流的字节数组提取出来
		// byte[] bs = bout.toByteArray();

		// 通过提取出来的字节数组构造一个输入流，此输入流模拟客户端的输入流
		// 真实测试时，通过获取Servlet的输入流，把其转换成DataInputStream流进行操作
		// DataInputStream in = new DataInputStream(new
		// ByteArrayInputStream(bs));
		// Packet p = translateObjectFromStream(Packet.class, in);

		// ByteArrayOutputStream bout2 = new ByteArrayOutputStream();
		// DataOutputStream dout2 = new DataOutputStream(bout2);

		// p为一个对象，把其直接转换成客户端二进制流协议
		// translateObjectToStream(p, dout2);
		// dout2可以模拟直接输出到客户端，把其转换成Servlet的输出流，输出给客户端

	}
}
